﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;


namespace EVEMap
{
    /// <summary>
    /// Representation of the rows in the mapSolarSystem table, with added data for routing.
    /// </summary>
    public class eveSolarSystem
    {
        #region members
        /// <summary>stuff from the static dump></summary>
        int solarSystemID;
        int regionID;
        int constellationID;
        string solarSystemName;
        double security;
        double x, y, z;

        /// <summary>
        /// Computed from mapSolarSystemJumps: the stargates in this system
        /// </summary>
        List<int> adjacentSystems;

        /// <summary>
        /// for computing routes
        /// </summary>
        int distanceFromStart;

        /// <summary>
        /// The stations in this system
        /// </summary>
        List<eveStation> stations;

        /// <summary>
        /// computed cumulative value of the assets in this system
        /// </summary>
        double assetsValue;

        List<int> routeToHub;
        #endregion

        public eveSolarSystem(System.Data.DataRow row)
        {
            createHelper(row);
            DataRow[] outboundJumps = row.GetChildRows("OutboundJumps");
            foreach (DataRow jumpRow in outboundJumps)
            {
                adjacentSystems.Add(Convert.ToInt32(jumpRow["toSolarSystemID"]));
            }

        }

        public eveSolarSystem(eveSolarSystem other)
        {
            solarSystemID = other.solarSystemID;
            regionID = other.regionID;
            constellationID = other.constellationID;
            solarSystemName = other.solarSystemName;
            security = other.security;
            assetsValue = other.assetsValue;
            distanceFromStart = other.distanceFromStart;
            adjacentSystems = new List<int>(other.adjacentSystems);
            if (other.routeToHub != null)
                routeToHub = new List<int>(other.routeToHub);
            if (other.stations != null)
            {
                stations = new List<eveStation>();
                foreach (eveStation station in other.stations)
                {
                    eveStation s = new eveStation(station);
                    stations.Add(s);
                }
            }
        }

        public void AddStations(System.Data.DataRow row)
        {
            stations = new List<eveStation>();
            DataRow[] stationRows = row.GetChildRows("sysStations");
            foreach (DataRow stationRow in stationRows)
            {
                eveStation tmp = new eveStation(stationRow);
                stations.Add(tmp);
                assetsValue += tmp.AssetsValue;
            }
        }

        private void createHelper(System.Data.DataRow row)
        {
            solarSystemID = Convert.ToInt32(row["solarSystemID"]);
            regionID = Convert.ToInt32(row["regionID"]);
            constellationID = Convert.ToInt32(row["constellationID"]);
            solarSystemName = Convert.ToString(row["solarSystemName"]);
            security = Convert.ToDouble(row["security"]);
            x = Convert.ToDouble(row["x"]);
            y = Convert.ToDouble(row["y"]);
            z = Convert.ToDouble(row["z"]);


            distanceFromStart = int.MaxValue;
            adjacentSystems = new List<int>();
        }

        /// <summary>
        /// Identify a system as having multple stations with assets where at least one station
        /// other than the richest one has at least threshold value of assets.
        /// </summary>
        /// <param name="threshold">The minimum value of a station's assets considered worth couriering to a station in the same system</param>
        /// <returns>true if the system is worth consolidating</returns>
        public bool needsConsolidation(double threshold)
        {
            int count = 0;
            if (stations.Count < 2)
                return false;
            stations.Sort((x, y) => y.AssetsValue.CompareTo(x.AssetsValue));
            foreach (eveStation station in stations)
            {
                if (station.AssetsValue >= threshold && station != stations.First())
                    ++count;
            }
            return count > 0;
        }

        public int ID
        {
            get
            {
                return solarSystemID;
            }
        }

        public string Name
        {
            get
            {
                return solarSystemName;
            }
        }

        public int RouteDistance
        {
            get
            {
                return distanceFromStart;
            }
            set
            {
                distanceFromStart = value;
            }
        }

        public List<int> Jumps
        {
            get
            {
                return adjacentSystems;
            }
        }

        public double AssetsValue
        {
            get
            {
                return assetsValue;
            }
        }

        public double Security
        {
            get
            {
                return security;
            }
        }

        public List<int> Route
        {
            get
            {
                return routeToHub;
            }
            set
            {
                routeToHub = value;
            }
        }

        /// <summary>
        /// The assets list of the station with the most assets
        /// </summary>
        public coalesceAssetsList BiggestStationAssets
        {
            get
            {
                if (stations.Count > 0)
                {
                    stations.Sort((x, y) => y.AssetsValue.CompareTo(x.AssetsValue));
                    eveStation tmp = stations[0];
                    return new coalesceAssetsList(tmp);
                }
                return null;
            }
        }

        /// <summary>
        /// the station in this system with the most valuable assets
        /// </summary>
        public eveStation BiggestAssetsStation
        {
            get
            {
                if (stations.Count > 0)
                {
                    stations.Sort((x, y) => y.AssetsValue.CompareTo(x.AssetsValue));
                    return stations[0];
                }
                return null;
            }
        }

        public bool AssetsPinned
        {
            get
            {
                if (stations.Count > 0)
                {
                    foreach (eveStation sta in stations)
                    {
                        if (sta.AssetsPinned)
                            return true;
                    }
                }
                return false;
            }
        }

    }

    /// <summary>
    /// Representation of a row in the mapSolarSystemJumps table
    /// </summary>
    class eveSolarSystemJump
    {

    }

    public class eveStation
    {
        #region members
        int stationID;
        int solarSystemID;
        string name;
        List<assetStack> assets;
        double assetsValue;
        /// <summary>
        /// flag indicates that the assets in this station are pinned in place during coalesce
        /// </summary>
        bool assetsPinned;
        #endregion

        public eveStation(System.Data.DataRow row)
        {
            assetsPinned = false;
            stationID = Convert.ToInt32(row["stationID"]);
            solarSystemID = Convert.ToInt32(row["solarSystemID"]);
            name = Convert.ToString(row["stationName"]);
            DataRow[] assetStacks = row.GetChildRows("stationAssets");
            assets = new List<assetStack>();
            foreach (DataRow assetRow in assetStacks)
            {
                assetStack tmp = new assetStack(assetRow);
                assets.Add(tmp);
                assetsValue += tmp.Value;
            }
        }

        public eveStation(eveStation other)
        {
            assetsPinned = other.assetsPinned;
            stationID = other.stationID;
            solarSystemID = other.solarSystemID;
            name = other.name;
            assets = new List<assetStack>();
            foreach (assetStack asset in other.assets)
            {
                assetStack a = new assetStack(asset);
                assets.Add(a);
            }
        }

        //public void moveAssets(eveStation dest)
        //{
        //    dest.assets.AddRange(assets);
        //    dest.assetsPinned = true;
        //    assets.Clear();
        //}

        public int ID
        {
            get
            {
                return stationID;
            }
        }

        public string Name
        {
            get
            {
                return name;
            }
        }

        public int SystemID
        {
            get
            {
                return solarSystemID;
            }
        }

        public double AssetsValue
        {
            get
            {
                assetsValue = 0;
                foreach (assetStack asset in assets)
                    assetsValue += asset.Value;
                return assetsValue;
            }
        }

        public bool AssetsPinned
        {
            get
            {
                return assetsPinned;
            }
            set 
            { 
                assetsPinned = value; 
            }
        }

        public List<assetStack> Assets
        {
            get
            {
                return assets;
            }
        }
    }


    public class routeJunction
    {
        public int solarSystem1; // where we started from: the one with the bigger stack
        public int solarSystem2; // what we're comparing to solarSystem1
        public int junctureSytem; // where the routes converge, if any
        public int hubDistance; // how far from the hub is the convergance?
        public int junctionDistance; // how far is solarSystem2 from the junction?
    }

}
